
package com.hlkj.pay.app.merchant.ext.impl.gtzfpay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.date.DatePattern;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.constant.GtzfPayConstant;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.GtzfPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.GtzfpayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.utils.GtzfPayRsaUtil;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.utils.HttpUtils;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.order.RefundOrderDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.*;

/**
 * 国通 正扫 反扫 通用处理
 * 
 * @author HlpayTeam
 * @date 2024/10/11 16:22
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class GtzfPaySceneCommonPayOrder {

    /**
     * 国通查询支付订单
     *
     * @param channelPayOrderQueryContext
     */
    public void commonQueryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderQueryContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        GtzfPayConfig config = JsonUtils.parseObject(channelConfig, GtzfPayConfig.class);
        PayOrderDO payOrderDO = channelPayOrderQueryContext.getPayOrderDO();
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderQueryContext.getMerchantAppChannelDO();
        try {

            Map<String, Object> params = new HashMap<>();
            params.put("orderNo", payOrderDO.getPayOrderNo());
            params.put("agetId", config.getAgetId());
            params.put("custId", merchantAppChannelDO.getSubMchId());
            params.put("orderTime", DateUtils.dateToString(payOrderDO.getCreateTime(), DatePattern.PURE_DATE_PATTERN));
            params.put("timeStamp", DateUtils.getDateString(DatePattern.PURE_DATETIME_PATTERN));
            params.put("version", "1.0.0");
            params.put("sign", GtzfPayRsaUtil.encrypt(GtzfPayRsaUtil.getContent(JSONUtil.parseObj(params)), config.getMchPublicKey()));

            log.info("国通订单查询req参数:{}", JsonUtils.toJsonString(params));
            String url = domain(channelPayOrderQueryContext.isTest()) + GtzfPayConstant.TRADE_QUERY;
            String response = HttpUtils.post(url, JsonUtils.toJsonString(params));
            log.info("国通订单查询返回参数:{}", response);
            // 响应报文验签
            JSONObject rspBody = JsonUtils.parseObj(response);
            PayOrderDO updartePayOrderDO = new PayOrderDO();
            updartePayOrderDO.setBankCode(rspBody.getStr("code"));
            updartePayOrderDO.setBankMsg(rspBody.getStr("msg"));
            if (!rspBody.containsKey("data")) {
                String respDesc = rspBody.getStr("msg");
                channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderQueryContext.setRemark(respDesc);
                } else {
                    channelPayOrderQueryContext.setRemark("国通查询订单返回错误信息为空,错误码为:" + rspBody.getStr("code"));
                }
                return;
            }
            switch (rspBody.getStr("code")) {
                case "000000":
                    updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.SUCCESS.getCode());
                    break;
                case "222222":
                    updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.PAYING.getCode());
                    break;
                default:
                    updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.FAIL.getCode());
                    break;
            }
            JSONObject respStateInfo = rspBody.getJSONObject("data");
            updartePayOrderDO.setInsOrderNo(respStateInfo.getStr("orderNo"));
            updartePayOrderDO.setChannelOrderNo(respStateInfo.getStr("payNo"));
            updartePayOrderDO.setUserId(respStateInfo.getStr("subOpenId"));
            updartePayOrderDO.setSuccessTime(DateUtils.shanghaiDate(respStateInfo.getStr("orderTime")));
            channelPayOrderQueryContext.setUpdartePayOrderDO(updartePayOrderDO);
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("国通查询支付订单请求失败 message:{}", e.getMessage(), e);
            channelPayOrderQueryContext.setRemark("国通查询支付订单请求失败,失败信息" + e.getMessage());
            channelPayOrderQueryContext.setProcessStatus(Boolean.FALSE);
        }
    }

    /**
     * 国通关闭订单
     *
     * @param channelPayOrderQueryContext
     */
    public void commonCloseChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
    }

    /**
     * 国通查询关闭订单状态
     *
     * @param channelPayOrderQueryContext
     */
    public void commonQueryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        // 国通无此接口
        PayOrderDO updartePayOrderDO = new PayOrderDO();
        updartePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.CLOSE.getCode());
        channelPayOrderQueryContext.setUpdartePayOrderDO(updartePayOrderDO);
    }

    /**
     * 国通订单退款
     *
     * @param channelRefundPayOrderContext
     */
    public void commonRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelRefundPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        GtzfPayConfig config = JsonUtils.parseObject(channelConfig, GtzfPayConfig.class);

        PayOrderDO payOrderDO = channelRefundPayOrderContext.getPayOrderDO();
        RefundOrderDO refundOrderDO = channelRefundPayOrderContext.getRefundOrderDO();
        MerchantAppChannelDO merchantAppChannelDO = channelRefundPayOrderContext.getMerchantAppChannelDO();
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("orderNo", refundOrderDO.getRefundOrderNo());
            params.put("oldTOrderNo", payOrderDO.getPayOrderNo());
            params.put("agetId", config.getAgetId());
            params.put("custId", merchantAppChannelDO.getSubMchId());
            params.put("refundAmount", MerchantUtils.YuanToFen(refundOrderDO.getRefundAmount()));
            params.put("tag", getPayTag(payOrderDO.getPayType()));
            params.put("timeStamp", DateUtils.getDateString(DatePattern.PURE_DATETIME_PATTERN));
            params.put("version", "1.0.0");
            //退款地址无效
//            params.put("asyncNotify", "https://test-api.hbhlpay.com/applyments.ffpay/test");
            params.put("sign", GtzfPayRsaUtil.encrypt(GtzfPayRsaUtil.getContent(JSONUtil.parseObj(params)), config.getMchPublicKey()));

            log.info("国通订单退款req参数:{}", JsonUtils.toJsonString(params));
            String url = domain(channelRefundPayOrderContext.isTest()) + GtzfPayConstant.TRADE_REFUND_APPLY;
            String response = HttpUtils.post(url, JsonUtils.toJsonString(params));
            log.info("国通订单退款返回参数:{}", response);
            // 响应报文验签
            JSONObject rspBody = JsonUtils.parseObj(response);
            if ("000000".equals(rspBody.getStr("code"))) {
                JSONObject respStateInfo = rspBody.getJSONObject("data");
                RefundOrderDO updateRefundOrderDO = new RefundOrderDO();
                switch (respStateInfo.getStr("orderStatus")) {
                    case "3":
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.FAIL.getCode());
                        break;
                    case "4":
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUND.getCode());
                        break;
                    default:
                        updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUNDING.getCode());
                        break;
                }
                channelRefundPayOrderContext.setUpdateRefundOrderDO(updateRefundOrderDO);
            }
            else {
                String respDesc = rspBody.getStr("msg");
                channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelRefundPayOrderContext.setRemark(respDesc);
                }
                else {
                    channelRefundPayOrderContext.setRemark("国通提交退款订单返回错误信息为空,错误码为:" + rspBody.getStr("code"));
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("国通提交退款订单请求失败 message:{}", e.getMessage(), e);
            channelRefundPayOrderContext.setRemark("国通提交退款订单请求失败,失败信息" + e.getMessage());
            channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    private String getPayTag(String payType) {
        switch (payType) {
            case "WECHAT":
                return "2";
            case "ALIPAY":
                return "1";
            case "UNION_APY":
                return "9";
        }
        return "";
    }

    /**
     * 国通订单退款状态查询
     *
     * @param channelRefundPayOrderContext
     */
    public void commonQueryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelRefundPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        GtzfPayConfig config = JsonUtils.parseObject(channelConfig, GtzfPayConfig.class);
        easyPayAppChannelParams(channelRefundPayOrderContext.getMerchantAppChannelDO(), config);

        RefundOrderDO refundOrderDO = channelRefundPayOrderContext.getRefundOrderDO();
        MerchantAppChannelDO merchantAppChannelDO = channelRefundPayOrderContext.getMerchantAppChannelDO();
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("orderNo", refundOrderDO.getRefundOrderNo());
            params.put("agetId", config.getAgetId());
            params.put("custId", merchantAppChannelDO.getSubMchId());
            params.put("timeStamp", DateUtils.getDateString(DatePattern.PURE_DATETIME_PATTERN));
            params.put("version", "1.0.0");
            params.put("sign", GtzfPayRsaUtil.encrypt(GtzfPayRsaUtil.getContent(JSONUtil.parseObj(params)), config.getMchPublicKey()));

            log.info("国通订单退款查询req参数:{}", JsonUtils.toJsonString(params));
            String url = domain(channelRefundPayOrderContext.isTest()) + GtzfPayConstant.TRADE_REFUND_QUERY;
            String response = HttpUtils.post(url, JsonUtils.toJsonString(params));
            log.info("国通订单退款查询返回参数:{}", response);

            JSONObject rspBody = JsonUtils.parseObj(response);
            RefundOrderDO updateRefundOrderDO = new RefundOrderDO();
            updateRefundOrderDO.setBankCode(rspBody.getStr("code"));
            updateRefundOrderDO.setBankMsg(rspBody.getStr("msg"));
            if (!rspBody.containsKey("data")) {
                String respDesc = rspBody.getStr("msg");
                channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelRefundPayOrderContext.setRemark(respDesc);
                } else {
                    channelRefundPayOrderContext.setRemark("国通查询退款订单返回错误信息为空,错误码为:" + rspBody.getStr("code"));
                }
                return;
            }
            switch (rspBody.getStr("code")) {
                case "000000":
                    updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.REFUND.getCode());
                    break;
                default:
                    updateRefundOrderDO.setRefundStatus(PayOrderEnums.REFUND_STATUS.FAIL.getCode());
                    break;
            }
            channelRefundPayOrderContext.setUpdateRefundOrderDO(updateRefundOrderDO);
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("国通退款订单查询请求失败 message:{}", e.getMessage(), e);
            channelRefundPayOrderContext.setRemark("国通退款订单查询请求失败,失败信息" + e.getMessage());
            channelRefundPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    public GtzfpayAppChannelParams easyPayAppChannelParams(MerchantAppChannelDO merchantAppChannelDO, GtzfPayConfig config) {
        GtzfpayAppChannelParams appChannelParams = JsonUtils.parseObject(merchantAppChannelDO.getAppConfigJson(), GtzfpayAppChannelParams.class);
        if (MerchantEnum.APP_CHANNEL_TYPE.MERCHANT_COMMON.getCode().equals(merchantAppChannelDO.getType())) {
            config.setMchPublicKey(appChannelParams.getMchPublicKey());
            config.setAgetId(appChannelParams.getAgetId());
        }
        return appChannelParams;
    }

    public String domain(boolean test) {
        return test ? GtzfPayConstant.PAY_ORDER_DOMAIN_TEST : GtzfPayConstant.PAY_ORDER_DOMAIN_PROD;
    }

    public Integer expireMinute(Long time) {
        if (time == null) {
            return 30;
        }
        return (int) (time - System.currentTimeMillis()) / 1000 / 60;
    }
}
